/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
 *
 * @file    mapi_osd.c
 * @brief   osd server function
 * @author  HiMobileCam NDK develop team
 * @date  2019-3-26
 */


#include <string.h>
#include <sys/prctl.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>
#include "hi_mapi_osd.h"
#include "hi_mapi_osd_define.h"
#include "mpi_vi.h"
#include "mpi_vpss.h"
#ifdef SUPPORT_STITCH
#include "mpi_avs.h"
#endif
#include "mpi_venc.h"
#include "mpi_vo.h"
#include "mpi_region.h"
#include "mapi_comm_inner.h"
#include "mapi_function_inner.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /*   End of #ifdef __cplusplus   */

#define IsASCII(a)              (((a) >= 0x00 && (a) <= 0x7F) ? 1 : 0)
#define BYTE_BITS               8
#define NOASCII_CHARACTER_BYTES 2 /*   Number of bytes occupied by each Chinese character   */

    /*   OSD Font Step In Lib, in bytes   */
#define OSD_LIB_FONT_W                 (g_stOsdFonts.u32FontWidth)
#define OSD_LIB_FONT_H                 (g_stOsdFonts.u32FontHeight)
#define OSD_LIB_FONT_STEP              (OSD_LIB_FONT_W * OSD_LIB_FONT_H / BYTE_BITS)
#define OSD_RATIO_COORDINATE_MAX_VALUE 100

#define MAPI_ADEC_WAIT_TIME_CHANGE_USLEEP_TIME (10 * 1000)
#define MAPI_ADEC_WAIT_UPDATE_TIME_USLEEP_TIME (500 * 1000)

/*   OSD Parameter   */
typedef struct tagOSD_PARAM_S {
    HI_MAPI_OSD_ATTR_S stAttr;
    SIZE_S stMaxSize;
    pthread_mutex_t mutexLock;
    HI_BOOL bInit; /*   OSD Attribute Set or not, Canbe modified only HI_MAPI_OSD_SetAttr   */
    HI_BOOL bStart;   /*   OSD start/stop Flag, Canbe modified only by HI_MAPI_OSD_Start/HI_MAPI_OSD_Stop   */
    HI_CHAR szStr[HI_MAPI_OSD_MAX_STR_LEN];
    RGN_TYPE_E enRgnType;
} OSD_PARAM_S;

/*  * OSD Module Init Flag
  Canbe modified only by HI_PDT_OSD_Init/HI_PDT_OSD_DeInit   */
static HI_BOOL g_bOsdInitFlg = HI_FALSE;

/*  * OSD Time Update Runing Flag
  Canbe modified only by HI_PDT_OSD_Init/HI_PDT_OSD_DeInit   */
static HI_BOOL g_bOsdTimeRun = HI_FALSE;

/*   OSD Fonts Lib, inited by HI_PDT_OSD_Init   */
static HI_MAPI_OSD_FONTS_S g_stOsdFonts;

/*   OSD Parameter Array   */
static OSD_PARAM_S g_astOSDParam[HI_MAPI_OSD_MAX_CNT];

/*   Time OSD Update Task Thread ID, created by HI_PDT_OSD_Init, destroyed by HI_MAPI_OSD_DeInit   */
static pthread_t g_pOsdTimeTskId = 0;

/*  *
* @brief   get time string with given format
* @param[in]pstTime : time struct, get current system time if null
* @param[in]enFmt : time string format, eg. YMD24H
* @param[out]pazStr : time string buffer
* @param[in]s32Len : time string buffer length
*/
static HI_VOID OSD_GetTimeStr(const struct tm* pstTime, HI_MAPI_OSD_TIMEFMT_E enFmt, HI_CHAR* pazStr, HI_S32 s32Len)
{
    /*   Get Time   */
    time_t nowTime;
    struct tm stTime = {
        0,
    };

    if (!pstTime) {
        time(&nowTime);
        localtime_r(&nowTime, &stTime);
        pstTime = &stTime;
    }

    /*   Generate Time String   */
    switch (enFmt) {
        case HI_MAPI_OSD_TIMEFMT_YMD24H:
        default:
            snprintf(pazStr, s32Len, "%04d-%02d-%02d %02d:%02d:%02d",
                     pstTime->tm_year + 1900, pstTime->tm_mon + 1, pstTime->tm_mday, // 1900 is struct tm year reference
                     pstTime->tm_hour, pstTime->tm_min, pstTime->tm_sec);
            break;
    }

    return;
}

static HI_S32 OSD_Ratio2Absolute(MPP_CHN_S stChn, const POINT_S* pstRatioCoor, POINT_S* pstAbsCoor)
{
    HI_S32 s32Ret = HI_SUCCESS;
    SIZE_S stImageSize;

    if (pstRatioCoor->s32X < 0 || pstRatioCoor->s32X > OSD_RATIO_COORDINATE_MAX_VALUE ||
        pstRatioCoor->s32Y < 0 || pstRatioCoor->s32Y > OSD_RATIO_COORDINATE_MAX_VALUE) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "invalide Ratio coordinate(%d,%d)\n", pstRatioCoor->s32X, pstRatioCoor->s32Y);
        return HI_MAPI_OSD_EILLEGAL_PARAM;
    }

    switch (stChn.enModId) {
        case HI_ID_VI: {
            VI_CHN_ATTR_S stChnAttr;
            s32Ret = HI_MPI_VI_GetChnAttr(stChn.s32DevId, stChn.s32ChnId, &stChnAttr);

            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_VI_GetChnAttr(%d, %d) fail,Error Code: [0x%08X]\n",
                    stChn.s32DevId, stChn.s32ChnId, s32Ret);
                return s32Ret;
            }

            stImageSize = stChnAttr.stSize;
            break;
        }

        case HI_ID_VPSS: {
            VPSS_CHN_ATTR_S stChnAttr;
            s32Ret = HI_MPI_VPSS_GetChnAttr(stChn.s32DevId, stChn.s32ChnId, &stChnAttr);

            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_VPSS_GetChnAttr(%d, %d) fail,Error Code: [0x%08X]\n",
                    stChn.s32DevId, stChn.s32ChnId, s32Ret);
                return s32Ret;
            }

            stImageSize.u32Width = stChnAttr.u32Width;
            stImageSize.u32Height = stChnAttr.u32Height;
            break;
        }

        case HI_ID_AVS: {
#ifdef SUPPORT_STITCH
            AVS_CHN_ATTR_S stChnAttr;
            s32Ret = HI_MPI_AVS_GetChnAttr(stChn.s32DevId, stChn.s32ChnId, &stChnAttr);

            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_AVS_GetChnAttr(%d, %d) fail,Error Code: [0x%08X]\n",
                    stChn.s32DevId, stChn.s32ChnId, s32Ret);
                return s32Ret;
            }

            stImageSize.u32Width = stChnAttr.u32Width;
            stImageSize.u32Height = stChnAttr.u32Height;
#else
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "stitch is not support.\n");
            return HI_MAPI_OSD_ENOT_PERM;
#endif
            break;
        }

        case HI_ID_VENC: {
            VENC_CHN_ATTR_S stChnAttr;
            s32Ret = HI_MPI_VENC_GetChnAttr(stChn.s32ChnId, &stChnAttr);

            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_VENC_GetChnAttr(%d) fail,Error Code: [0x%08X]\n",
                    stChn.s32ChnId, s32Ret);
                return s32Ret;
            }

            stImageSize.u32Width = stChnAttr.stVencAttr.u32PicWidth;
            stImageSize.u32Height = stChnAttr.stVencAttr.u32PicHeight;
            break;
        }

        case HI_ID_VO: {
            VO_CHN_ATTR_S stChnAttr;
            s32Ret = HI_MPI_VO_GetChnAttr(stChn.s32DevId, stChn.s32ChnId, &stChnAttr);

            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_VO_GetChnAttr(%d,%d) fail,Error Code: [0x%08X]\n",
                    stChn.s32DevId, stChn.s32ChnId, s32Ret);
                return s32Ret;
            }

            stImageSize.u32Width = stChnAttr.stRect.u32Width;
            stImageSize.u32Height = stChnAttr.stRect.u32Height;
            break;
        }

        default:
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "invalide mode id [%d]\n", stChn.enModId);
            return HI_MAPI_OSD_EILLEGAL_PARAM;
    }

    pstAbsCoor->s32X = MAPI_ALIGN(stImageSize.u32Width * pstRatioCoor->s32X /
        OSD_RATIO_COORDINATE_MAX_VALUE, 2); // 2: s32X align at 2 pixel
    pstAbsCoor->s32Y = MAPI_ALIGN(stImageSize.u32Height * pstRatioCoor->s32Y /
        OSD_RATIO_COORDINATE_MAX_VALUE, 2); // 2: s32X align at 2 pixel
    return HI_SUCCESS;
}

static HI_S32 OSD_GetNonASCNum(HI_CHAR* string, HI_S32 len)
{
    HI_S32 i;
    HI_S32 n = 0;
    for (i = 0; i < len; i++) {
        if (string[i] == '\0') {
            break;
        }
        if (!IsASCII(string[i])) {
            i++;
            n++;
        }
    }

    return n;
}

static HI_S32 OSD_UpdateTextBitmap(RGN_HANDLE RgnHdl, const HI_MAPI_OSD_CONTENT_S* pstContent)
{
    HI_S32 s32Ret;
    HI_U32 u32CanvasWidth,u32CanvasHeight,u32BgColor;
    SIZE_S stFontSize;
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[RgnHdl];
    HI_S32 s32StrLen = strnlen(pstOsdParam->szStr, HI_MAPI_OSD_MAX_STR_LEN);
    HI_S32 NonASCNum = OSD_GetNonASCNum(pstOsdParam->szStr, s32StrLen);
    if (pstContent->enType == HI_MAPI_OSD_TYPE_STRING) {
        u32CanvasWidth =
            pstContent->stStrContent.stFontSize.u32Width * (s32StrLen - NonASCNum * (NOASCII_CHARACTER_BYTES - 1));
        u32CanvasHeight = pstContent->stStrContent.stFontSize.u32Height;
        stFontSize.u32Width = pstContent->stStrContent.stFontSize.u32Width;
        stFontSize.u32Height = pstContent->stStrContent.stFontSize.u32Height;
        u32BgColor = pstContent->stStrContent.u32BgColor;
    } else {
        u32CanvasWidth =
            pstContent->stTimeContent.stFontSize.u32Width * (s32StrLen - NonASCNum * (NOASCII_CHARACTER_BYTES - 1));
        u32CanvasHeight = pstContent->stTimeContent.stFontSize.u32Height;
        stFontSize.u32Width = pstContent->stTimeContent.stFontSize.u32Width;
        stFontSize.u32Height = pstContent->stTimeContent.stFontSize.u32Height;
        u32BgColor = pstContent->stTimeContent.u32BgColor;
    }

    RGN_CANVAS_INFO_S stCanvasInfo;
    s32Ret = HI_MPI_RGN_GetCanvasInfo(RgnHdl, &stCanvasInfo);

    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_RGN_GetCanvasInfo fail,RgnHdl[%d] Error Code: [0x%08X]\n",
            RgnHdl, s32Ret);
        return s32Ret;
    }

    /*   Generate Bitmap   */
    HI_U16 *puBmData = (HI_U16 *)(HI_UL)stCanvasInfo.u64VirtAddr;
    HI_U32 u32BmRow, u32BmCol; /*   Bitmap Row/Col Index   */

    for (u32BmRow = 0; u32BmRow < u32CanvasHeight; ++u32BmRow) {
        HI_S32 NonASCShow = 0;
        for (u32BmCol = 0; u32BmCol < u32CanvasWidth; ++u32BmCol) {
            /*   Bitmap Data Offset for the point   */
            HI_S32 s32BmDataIdx = u32BmRow * stCanvasInfo.u32Stride / 2 + u32BmCol;
            /*   Character Index in Text String   */
            HI_S32 s32CharIdx = u32BmCol / stFontSize.u32Width;
            HI_S32 s32StringIdx = s32CharIdx + NonASCShow * (NOASCII_CHARACTER_BYTES - 1);
            if (NonASCNum > 0 && s32CharIdx > 0) {
                NonASCShow = OSD_GetNonASCNum(pstOsdParam->szStr, s32StringIdx);
                s32StringIdx = s32CharIdx + NonASCShow * (NOASCII_CHARACTER_BYTES - 1);
            }
            /*   Point Row/Col Index in Character   */
            HI_S32 s32CharCol = (u32BmCol - (stFontSize.u32Width * s32CharIdx)) * OSD_LIB_FONT_W /
                                stFontSize.u32Width;
            HI_S32 s32CharRow = u32BmRow * OSD_LIB_FONT_H / stFontSize.u32Height;
            HI_S32 s32HexOffset = s32CharRow * OSD_LIB_FONT_W / BYTE_BITS + s32CharCol / BYTE_BITS;
            HI_S32 s32BitOffset = s32CharCol % BYTE_BITS;
            HI_U8 *FontMod = NULL;
            HI_S32 FontModLen = 0;
            if (HI_SUCCESS == g_stOsdFonts.pfnGetFontMod(&pstOsdParam->szStr[s32StringIdx], &FontMod, &FontModLen)) {
                if (FontMod != NULL && s32HexOffset < FontModLen) {
                    HI_U8 temp = FontMod[s32HexOffset];
                    if ((temp >> ((BYTE_BITS - 1) - s32BitOffset)) & 0x1) {
                        puBmData[s32BmDataIdx] = (HI_U16)pstContent->u32Color;
                    } else {
                        puBmData[s32BmDataIdx] = (HI_U16)u32BgColor;
                    }
                    continue;
                }
            }
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "GetFontMod Fail\n");
            return HI_FAILURE;
        }

        for (u32BmCol = u32CanvasWidth; u32BmCol < g_astOSDParam[RgnHdl].stMaxSize.u32Width; ++u32BmCol) {
            HI_S32 s32BmDataIdx = u32BmRow * stCanvasInfo.u32Stride / 2 + u32BmCol;
            puBmData[s32BmDataIdx] = (HI_U16)u32BgColor;
        }
    }

    for (u32BmRow = u32CanvasHeight; u32BmRow < g_astOSDParam[RgnHdl].stMaxSize.u32Height; ++u32BmRow) {
        for (u32BmCol = 0; u32BmCol < g_astOSDParam[RgnHdl].stMaxSize.u32Width; ++u32BmCol) {
            HI_S32 s32BmDataIdx = u32BmRow * stCanvasInfo.u32Stride / 2 + u32BmCol;
            puBmData[s32BmDataIdx] = (HI_U16)u32BgColor;
        }
    }

    stCanvasInfo.enPixelFmt = PIXEL_FORMAT_ARGB_1555;
    stCanvasInfo.stSize.u32Width = u32CanvasWidth;
    stCanvasInfo.stSize.u32Height = u32CanvasHeight;

    s32Ret = HI_MPI_RGN_UpdateCanvas(RgnHdl);

    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_RGN_UpdateCanvas fail,RgnHdl[%d] Error Code: [0x%08X]\n",
            RgnHdl, s32Ret);
        return s32Ret;
    }

    return s32Ret;
}

static HI_S32 OSD_AttachRgn(RGN_HANDLE RgnHdl, const HI_MAPI_OSD_DISP_ATTR_S* pstDispAttr,
    const HI_MAPI_OSD_CONTENT_S* pstOsdContent)
{
    HI_S32 s32Ret = HI_SUCCESS;
    RGN_CHN_ATTR_S stRgnChnAttr;
    MPP_CHN_S stChn;

    stChn.s32DevId = pstDispAttr->ModHdl;
    stChn.s32ChnId = pstDispAttr->ChnHdl;
    memset(&stRgnChnAttr, 0x0, sizeof(RGN_CHN_ATTR_S));
    stRgnChnAttr.bShow = pstDispAttr->bShow;
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[RgnHdl];
    stRgnChnAttr.enType = pstOsdParam->enRgnType;

    switch (pstDispAttr->enBindedMod) {
        case HI_MAPI_OSD_BINDMOD_VCAP:
            stChn.enModId = HI_ID_VI;
            break;

        case HI_MAPI_OSD_BINDMOD_VPROC:
            stChn.enModId = HI_ID_VPSS;
            break;

        case HI_MAPI_OSD_BINDMOD_STITCH:
#ifdef SUPPORT_STITCH
            stChn.enModId = HI_ID_AVS;
            break;
#else
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "stitch is not support.\n");
            return HI_MAPI_OSD_ENOT_PERM;
#endif

        case HI_MAPI_OSD_BINDMOD_VENC:
            stChn.enModId = HI_ID_VENC;
            stChn.s32DevId = 0;
            stRgnChnAttr.unChnAttr.stOverlayChn.enAttachDest = pstDispAttr->enAttachDest;
            break;

        case HI_MAPI_OSD_BINDMOD_DISP:
            stChn.enModId = HI_ID_VO;
            break;

        default:
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "RgnHdl[%d] invalide bind mode [%d]\n", RgnHdl, pstDispAttr->enBindedMod);
            return HI_MAPI_OSD_EILLEGAL_PARAM;
    }

    POINT_S stStartPos;

    if (pstDispAttr->enCoordinate == HI_MAPI_OSD_COORDINATE_RATIO_COOR) {
        s32Ret = OSD_Ratio2Absolute(stChn, &pstDispAttr->stStartPos, &stStartPos);
        if (s32Ret != HI_SUCCESS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD_Ratio2Absolute fail,RgnHdl[%d] Error Code: [0x%08X]\n",
                RgnHdl, s32Ret);
            return s32Ret;
        }
    } else {
        stStartPos = pstDispAttr->stStartPos;
    }

    if (stRgnChnAttr.enType == OVERLAYEX_RGN) {
        stRgnChnAttr.unChnAttr.stOverlayExChn.stPoint.s32X = stStartPos.s32X;
        stRgnChnAttr.unChnAttr.stOverlayExChn.stPoint.s32Y = stStartPos.s32Y;
        stRgnChnAttr.unChnAttr.stOverlayExChn.u32BgAlpha = pstDispAttr->u32BgAlpha;
        stRgnChnAttr.unChnAttr.stOverlayExChn.u32FgAlpha = pstDispAttr->u32FgAlpha;
        stRgnChnAttr.unChnAttr.stOverlayExChn.u32Layer = 0;
    } else if (stRgnChnAttr.enType == OVERLAY_RGN) {
        stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = stStartPos.s32X;
        stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = stStartPos.s32Y;
        stRgnChnAttr.unChnAttr.stOverlayChn.u32BgAlpha = pstDispAttr->u32BgAlpha;
        stRgnChnAttr.unChnAttr.stOverlayChn.u32FgAlpha = pstDispAttr->u32FgAlpha;
        stRgnChnAttr.unChnAttr.stOverlayChn.u32Layer = 0;
    } else {
        HI_U32 i = 0; // Four points for recording quadrilateral
        stRgnChnAttr.unChnAttr.stCoverExChn.u32Layer = 0;
        stRgnChnAttr.unChnAttr.stCoverExChn.u32Color = pstOsdContent->u32Color;
        stRgnChnAttr.unChnAttr.stCoverExChn.enCoverType = AREA_QUAD_RANGLE;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.bSolid = HI_FALSE;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.u32Thick = 4;     // 4: Width of the edge
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[i].s32X =
            stStartPos.s32X;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[i++].s32Y =
            stStartPos.s32Y;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[i].s32X =
            stStartPos.s32X + pstOsdContent->stCircleContent.u32Width;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[i++].s32Y =
            stStartPos.s32Y;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[i].s32X =
            stStartPos.s32X;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[i++].s32Y =
            stStartPos.s32Y + pstOsdContent->stCircleContent.u32Height;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[i].s32X =
            stStartPos.s32X + pstOsdContent->stCircleContent.u32Width;
        stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[i].s32Y =
            stStartPos.s32Y + pstOsdContent->stCircleContent.u32Height;

    }

    s32Ret = HI_MPI_RGN_AttachToChn(RgnHdl, &stChn, &stRgnChnAttr);

    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_RGN_AttachToChn fail,RgnHdl[%d] stChn[%d,%d,%d] Error Code: [0x%08X]\n",
                       RgnHdl, stChn.enModId, stChn.s32DevId, stChn.s32ChnId, s32Ret);
        return s32Ret;
    }

    return HI_SUCCESS;
}

static HI_BOOL OSD_CheckIfBindVenc(const HI_MAPI_OSD_ATTR_S* pstAttr)
{
    HI_U32 u32DispIdx;
    for (u32DispIdx = 0; u32DispIdx < pstAttr->u32DispNum; ++u32DispIdx) {
        if (pstAttr->astDispAttr[u32DispIdx].enBindedMod == HI_MAPI_OSD_BINDMOD_VENC) {
            return HI_TRUE;
        }
    }
    return HI_FALSE;
}

static HI_VOID OSD_GetMaxSize(HI_MAPI_OSD_ATTR_S* pstAttr, SIZE_S* pstOsdSize)
{
    HI_U32 u32StrLen = strnlen(pstAttr->stContent.stStrContent.szStr, HI_MAPI_OSD_MAX_STR_LEN);
    HI_U32 u32Width;
    HI_U32 u32Height;

    if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_BITMAP) {
        u32Width = pstAttr->stContent.stBitmapContent.u32Width;
        u32Height = pstAttr->stContent.stBitmapContent.u32Height;
    } else if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_STRING) {
        u32Width = u32StrLen * pstAttr->stContent.stStrContent.stFontSize.u32Width;
        u32Height = pstAttr->stContent.stStrContent.stFontSize.u32Height;
    } else if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_CIRCLE) {
        u32Width = pstAttr->stContent.stCircleContent.u32Width;
        u32Height = pstAttr->stContent.stCircleContent.u32Height;
    } else {
        HI_CHAR szTimeStr[HI_MAPI_OSD_MAX_STR_LEN];
        OSD_GetTimeStr(NULL, pstAttr->stContent.stTimeContent.enTimeFmt, szTimeStr,
            HI_MAPI_OSD_MAX_STR_LEN);
        u32StrLen = strnlen(szTimeStr, HI_MAPI_OSD_MAX_STR_LEN);
        u32Width = u32StrLen * pstAttr->stContent.stTimeContent.stFontSize.u32Width;
        u32Height = pstAttr->stContent.stTimeContent.stFontSize.u32Height;
    }

    pstOsdSize->u32Width = u32Width;
    pstOsdSize->u32Height = u32Height;
}

static HI_BOOL OSD_CheckIfRebuild(HI_S32 s32OsdIdx, HI_MAPI_OSD_ATTR_S* pstAttr, SIZE_S* pstOsdMaxSize)
{
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[s32OsdIdx];
    /* return HI_TRUE means go rebuild process */
    if ((pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_BITMAP) ||
        (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_STRING) ||
        (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_TIME)) {
        if ( pstOsdMaxSize->u32Width > pstOsdParam->stMaxSize.u32Width ||
            pstOsdMaxSize->u32Height > pstOsdParam->stMaxSize.u32Height) {
            return HI_TRUE;
        }
        /* if the string content is not extend, it will not rebuild for performance */
    }

    if (pstOsdParam->stAttr.u32DispNum != pstAttr->u32DispNum) {
        /* if disp num is added, we need attach new chn */
        return HI_TRUE;
    }

    return HI_FALSE;
}

static HI_VOID OSD_GetRgnAttr(RGN_HANDLE RgnHdl, const HI_MAPI_OSD_ATTR_S* pstAttr, RGN_ATTR_S* pstRgnAttr)
{

    SIZE_S stRgnSize = {0};
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[RgnHdl];
    HI_U32 u32StrLen = strnlen(pstOsdParam->szStr, HI_MAPI_OSD_MAX_STR_LEN);

    if(pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_BITMAP) {
        stRgnSize.u32Width = pstAttr->stContent.stBitmapContent.u32Width;
        stRgnSize.u32Height = pstAttr->stContent.stBitmapContent.u32Height;
        pstRgnAttr->enType = OSD_CheckIfBindVenc(pstAttr) ? OVERLAY_RGN : OVERLAYEX_RGN;
    } else if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_TIME) {
        stRgnSize.u32Width = u32StrLen * pstAttr->stContent.stTimeContent.stFontSize.u32Width;
        stRgnSize.u32Height = pstAttr->stContent.stTimeContent.stFontSize.u32Height;
        pstRgnAttr->enType = OSD_CheckIfBindVenc(pstAttr) ? OVERLAY_RGN : OVERLAYEX_RGN;
    } else if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_STRING) {
        stRgnSize.u32Width = u32StrLen * pstAttr->stContent.stStrContent.stFontSize.u32Width;
        stRgnSize.u32Height = pstAttr->stContent.stStrContent.stFontSize.u32Height;
        pstRgnAttr->enType = OSD_CheckIfBindVenc(pstAttr) ? OVERLAY_RGN : OVERLAYEX_RGN;
    } else {
        pstRgnAttr->enType = COVEREX_RGN;
    }

    if (pstRgnAttr->enType == OVERLAYEX_RGN) {
        pstRgnAttr->unAttr.stOverlayEx.enPixelFmt = PIXEL_FORMAT_ARGB_1555;
        pstRgnAttr->unAttr.stOverlayEx.u32BgColor = pstAttr->stContent.u32Color;
        pstRgnAttr->unAttr.stOverlayEx.stSize.u32Width = stRgnSize.u32Width;
        pstRgnAttr->unAttr.stOverlayEx.stSize.u32Height = stRgnSize.u32Height;
        pstRgnAttr->unAttr.stOverlayEx.u32CanvasNum = (HI_MAPI_OSD_TYPE_BITMAP == pstAttr->stContent.enType) ? 1 : 2;
    } else if (pstRgnAttr->enType == OVERLAY_RGN) {
        pstRgnAttr->unAttr.stOverlay.enPixelFmt = PIXEL_FORMAT_ARGB_1555;
        pstRgnAttr->unAttr.stOverlay.u32BgColor = pstAttr->stContent.u32Color;
        pstRgnAttr->unAttr.stOverlay.stSize.u32Width = stRgnSize.u32Width;
        pstRgnAttr->unAttr.stOverlay.stSize.u32Height = stRgnSize.u32Height;
        pstRgnAttr->unAttr.stOverlay.u32CanvasNum = (HI_MAPI_OSD_TYPE_BITMAP == pstAttr->stContent.enType) ? 1 : 2;
    }
    pstOsdParam->enRgnType = pstRgnAttr->enType;
    return;
}

static HI_S32 OSD_UpdateRgnContent(RGN_HANDLE RgnHdl, const HI_MAPI_OSD_ATTR_S* pstAttr)
{
    HI_S32 s32Ret = HI_SUCCESS;

    if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_BITMAP) {
        BITMAP_S stBitmap;
        stBitmap.enPixelFormat = pstAttr->stContent.stBitmapContent.enPixelFormat;
        stBitmap.u32Width = pstAttr->stContent.stBitmapContent.u32Width;
        stBitmap.u32Height = pstAttr->stContent.stBitmapContent.u32Height;
        stBitmap.pData = pstAttr->stContent.stBitmapContent.pData;
        s32Ret = HI_MPI_RGN_SetBitMap(RgnHdl, &stBitmap);

        if (s32Ret != HI_SUCCESS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD,
                "HI_MPI_RGN_SetBitMap fail,RgnHdl[%d] Error Code: [0x%08X]\n", RgnHdl, s32Ret);
            return s32Ret;
        }
    } else if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_TIME ||
        pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_STRING){
        s32Ret = OSD_UpdateTextBitmap(RgnHdl, &pstAttr->stContent);

        if (s32Ret != HI_SUCCESS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD_UpdateTextBitmap failed\n");
            return s32Ret;
        }
    }

    return s32Ret;

}

static HI_S32 OSD_CreateRgn(RGN_HANDLE RgnHdl, const HI_MAPI_OSD_ATTR_S* pstAttr)
{
    HI_S32 s32Ret;
    RGN_ATTR_S stRgnAttr;
    HI_U32 u32DispIdx;
    OSD_GetRgnAttr(RgnHdl,pstAttr,&stRgnAttr);
    s32Ret = HI_MPI_RGN_Create(RgnHdl, &stRgnAttr);
    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_RGN_Create fail,RgnHdl[%d] Error Code: [0x%08X]\n", RgnHdl, s32Ret);
        return s32Ret;
    }

    s32Ret = OSD_UpdateRgnContent(RgnHdl, pstAttr);
    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "osd update content fail,RgnHdl[%d] Error Code: [0x%08X]\n", RgnHdl, s32Ret);
        return s32Ret;
    }

    for (u32DispIdx = 0; u32DispIdx < pstAttr->u32DispNum; ++u32DispIdx) {
        s32Ret = OSD_AttachRgn(RgnHdl, &pstAttr->astDispAttr[u32DispIdx], &pstAttr->stContent);
        if (s32Ret != HI_SUCCESS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD_AttachRgn fail,RgnHdl[%d] Error Code: [0x%08X]\n", RgnHdl, s32Ret);
            return s32Ret;
        }
    }

    return HI_SUCCESS;
}

static HI_S32 OSD_DetachRgn(RGN_HANDLE RgnHdl, const HI_MAPI_OSD_DISP_ATTR_S* pstDispAttr)
{
    HI_S32 s32Ret;
    MPP_CHN_S stChn;

    stChn.s32DevId = pstDispAttr->ModHdl;
    stChn.s32ChnId = pstDispAttr->ChnHdl;
    switch (pstDispAttr->enBindedMod) {
        case HI_MAPI_OSD_BINDMOD_VCAP:
            stChn.enModId = HI_ID_VI;
            break;

        case HI_MAPI_OSD_BINDMOD_VPROC:
            stChn.enModId = HI_ID_VPSS;
            break;

        case HI_MAPI_OSD_BINDMOD_STITCH:
            stChn.enModId = HI_ID_AVS;
            break;

        case HI_MAPI_OSD_BINDMOD_VENC:
            stChn.s32DevId = 0;
            stChn.enModId = HI_ID_VENC;
            break;

        case HI_MAPI_OSD_BINDMOD_DISP:
            stChn.enModId = HI_ID_VO;
            break;

        default:
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "RgnHdl[%d] invalide bind mode [%d]\n", RgnHdl, pstDispAttr->enBindedMod);
            return HI_MAPI_OSD_EILLEGAL_PARAM;
    }

    s32Ret = HI_MPI_RGN_DetachFromChn(RgnHdl, &stChn);

    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD,
            "HI_MPI_RGN_DetachFromChn fail,RgnHdl[%d] stChn[%d,%d,%d] Error Code: [0x%08X]\n",
            RgnHdl, stChn.enModId, stChn.s32DevId, stChn.s32ChnId, s32Ret);
        return s32Ret;
    }

    return HI_SUCCESS;
}

static HI_S32 OSD_DestroyRgn(RGN_HANDLE RgnHdl, const HI_MAPI_OSD_ATTR_S* pstAttr)
{
    HI_S32 s32Ret;
    HI_U32 u32DispIdx;

    for (u32DispIdx = 0; u32DispIdx < pstAttr->u32DispNum; ++u32DispIdx) {
        s32Ret = OSD_DetachRgn(RgnHdl, &pstAttr->astDispAttr[u32DispIdx]);
        if (s32Ret != HI_SUCCESS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD_DetachRgn fail,RgnHdl[%d] Error Code: [0x%08X]\n", RgnHdl, s32Ret);
            return s32Ret;
        }
    }

    s32Ret = HI_MPI_RGN_Destroy(RgnHdl);

    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_RGN_Destroy fail,RgnHdl[%d] Error Code: [0x%08X]\n", RgnHdl, s32Ret);
        return s32Ret;
    }

    return HI_SUCCESS;
}

static HI_S32 OSD_UpdateDisplay(RGN_HANDLE RgnHdl, const HI_MAPI_OSD_ATTR_S* pstAttr)
{
    HI_S32 s32Ret;
    HI_U32 u32DispIdx;
    RGN_CHN_ATTR_S stRgnChnAttr;
    MPP_CHN_S stChn;

    for (u32DispIdx = 0; u32DispIdx < pstAttr->u32DispNum; ++u32DispIdx) {
        stChn.s32DevId = pstAttr->astDispAttr[u32DispIdx].ModHdl;
        stChn.s32ChnId = pstAttr->astDispAttr[u32DispIdx].ChnHdl;
        switch (pstAttr->astDispAttr[u32DispIdx].enBindedMod) {
            case HI_MAPI_OSD_BINDMOD_VCAP:
                stChn.enModId = HI_ID_VI;
                break;

            case HI_MAPI_OSD_BINDMOD_VPROC:
                stChn.enModId = HI_ID_VPSS;
                break;

            case HI_MAPI_OSD_BINDMOD_STITCH:
                stChn.enModId = HI_ID_AVS;
                break;

            case HI_MAPI_OSD_BINDMOD_VENC:
                stChn.s32DevId = 0;
                stChn.enModId = HI_ID_VENC;
                break;

            case HI_MAPI_OSD_BINDMOD_DISP:
                stChn.enModId = HI_ID_VO;
                break;

            default:
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "RgnHdl[%d] invalide bind mode [%d]\n",
                    RgnHdl, pstAttr->astDispAttr[u32DispIdx].enBindedMod);
                return HI_MAPI_OSD_EILLEGAL_PARAM;
        }

        s32Ret = HI_MPI_RGN_GetDisplayAttr(RgnHdl, &stChn, &stRgnChnAttr);

        if (s32Ret != HI_SUCCESS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD,
                "HI_MPI_RGN_GetDisplayAttr fail,RgnHdl[%d] stChn[%d,%d,%d] Error Code: [0x%08X]\n",
                RgnHdl, stChn.enModId, stChn.s32DevId, stChn.s32ChnId, s32Ret);
            return s32Ret;
        }

        stRgnChnAttr.bShow = pstAttr->astDispAttr[u32DispIdx].bShow;

        POINT_S stStartPos;

        if (pstAttr->astDispAttr[u32DispIdx].enCoordinate == HI_MAPI_OSD_COORDINATE_RATIO_COOR) {
            s32Ret = OSD_Ratio2Absolute(stChn, &pstAttr->astDispAttr[u32DispIdx].stStartPos, &stStartPos);

            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD_Ratio2Absolute fail,RgnHdl[%d] Error Code: [0x%08X]\n",
                    RgnHdl, s32Ret);
                return s32Ret;
            }
        } else {
            stStartPos = pstAttr->astDispAttr[u32DispIdx].stStartPos;
        }

        if (stRgnChnAttr.enType == OVERLAYEX_RGN) {
            stRgnChnAttr.unChnAttr.stOverlayExChn.stPoint.s32X = stStartPos.s32X;
            stRgnChnAttr.unChnAttr.stOverlayExChn.stPoint.s32Y = stStartPos.s32Y;
            stRgnChnAttr.unChnAttr.stOverlayExChn.u32BgAlpha = pstAttr->astDispAttr[u32DispIdx].u32BgAlpha;
            stRgnChnAttr.unChnAttr.stOverlayExChn.u32FgAlpha = pstAttr->astDispAttr[u32DispIdx].u32FgAlpha;
        } else if (stRgnChnAttr.enType == OVERLAY_RGN) {
            stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = stStartPos.s32X;
            stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = stStartPos.s32Y;
            stRgnChnAttr.unChnAttr.stOverlayChn.u32BgAlpha = pstAttr->astDispAttr[u32DispIdx].u32BgAlpha;
            stRgnChnAttr.unChnAttr.stOverlayChn.u32FgAlpha = pstAttr->astDispAttr[u32DispIdx].u32FgAlpha;
        } else if (stRgnChnAttr.enType == COVEREX_RGN) {
            stRgnChnAttr.unChnAttr.stCoverExChn.enCoverType = AREA_QUAD_RANGLE;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.bSolid = HI_FALSE;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.u32Thick = 4;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[0].s32X = stStartPos.s32X;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[0].s32Y = stStartPos.s32Y;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[1].s32X =
                stStartPos.s32X + pstAttr->stContent.stCircleContent.u32Width;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[1].s32Y = stStartPos.s32Y;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[2].s32X = stStartPos.s32X;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[2].s32Y =
                stStartPos.s32Y + pstAttr->stContent.stCircleContent.u32Height;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[3].s32X =
                stStartPos.s32X + pstAttr->stContent.stCircleContent.u32Width;
            stRgnChnAttr.unChnAttr.stCoverExChn.stQuadRangle.stPoint[3].s32Y =
                stStartPos.s32Y + pstAttr->stContent.stCircleContent.u32Height;
            stRgnChnAttr.unChnAttr.stCoverExChn.u32Color = pstAttr->stContent.u32Color;
        }

        s32Ret = HI_MPI_RGN_SetDisplayAttr(RgnHdl, &stChn, &stRgnChnAttr);

        if (s32Ret != HI_SUCCESS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD,
                "HI_MPI_RGN_SetDisplayAttr fail,RgnHdl[%d] stChn[%d,%d,%d] Error Code: [0x%08X]\n",
                RgnHdl, stChn.enModId, stChn.s32DevId, stChn.s32ChnId, s32Ret);
            return s32Ret;
        }
    }

    return HI_SUCCESS;
}


static HI_S32 OSD_Start(HI_S32 s32OsdIdx)
{
    HI_S32 s32Ret;
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[s32OsdIdx];

    /*   Time OSD: Update time string and bitmap   */
    if (pstOsdParam->stAttr.stContent.enType == HI_MAPI_OSD_TYPE_TIME) {
        OSD_GetTimeStr(NULL, pstOsdParam->stAttr.stContent.stTimeContent.enTimeFmt, pstOsdParam->szStr,
                       HI_MAPI_OSD_MAX_STR_LEN);
    }

    s32Ret = OSD_CreateRgn(s32OsdIdx, &pstOsdParam->stAttr);

    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD_CreateRgn s32OsdIdx[%d] failed:[0x%08X]\n", s32OsdIdx, s32Ret);
        return s32Ret;
    }

    pstOsdParam->bStart = HI_TRUE;
    return HI_SUCCESS;
}

static HI_S32 OSD_Stop(HI_S32 s32OsdIdx)
{
    HI_S32 s32Ret;
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[s32OsdIdx];

    s32Ret = OSD_DestroyRgn(s32OsdIdx, &pstOsdParam->stAttr);

    if (s32Ret != HI_SUCCESS) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD_DestroyRgn s32OsdIdx[%d] failed:[0x%08X]\n", s32OsdIdx, s32Ret);
        return s32Ret;
    }

    pstOsdParam->bStart = HI_FALSE;
    return HI_SUCCESS;
}

static HI_S32 OSD_CheckStitchModeAttr(HI_MAPI_OSD_ATTR_S* pstAttr)
{
#ifdef SUPPORT_STITCH
    HI_U32 i;
    HI_S32 s32Ret;
    AVS_GRP_ATTR_S stGrpAttr;

    CHECK_MAPI_NULL_PTR_RET(HI_MAPI_MOD_OSD, pstAttr, HI_MAPI_OSD_ENULL_PTR);

    for (i = 0; i < HI_MAPI_OSD_MAX_DISP_CNT; i++) {
        if ((pstAttr->astDispAttr[i].enBindedMod == HI_MAPI_OSD_BINDMOD_STITCH) &&
            (pstAttr->astDispAttr[i].enCoordinate == HI_MAPI_OSD_COORDINATE_RATIO_COOR)) {
            s32Ret = HI_MPI_AVS_GetGrpAttr(pstAttr->astDispAttr[i].ModHdl, &stGrpAttr);

            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "HI_MPI_AVS_GetGrpAttr fail, stitchHdl[%d] Error Code: [0x%08X]\n",
                    pstAttr->astDispAttr[i].ModHdl, s32Ret);
                return s32Ret;
            }

            if (stGrpAttr.enMode != AVS_MODE_BLEND) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "not support ratio coordinate when stitch mode is AVS_MODE_BLEND.\n");
                return HI_MAPI_OSD_EILLEGAL_PARAM;
            }
        }
    }

#endif

    return HI_SUCCESS;
}

HI_S32 OSD_CheckAttr(HI_S32 s32OsdIdx, HI_MAPI_OSD_ATTR_S* pstAttr)
{
    HI_S32 s32Ret;
    /*   Check Input Param   */
    CHECK_MAPI_NULL_PTR_RET(HI_MAPI_MOD_OSD, pstAttr, HI_MAPI_OSD_ENULL_PTR);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32OsdIdx >= 0, HI_MAPI_OSD_EHANDLE_ILLEGAL);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32OsdIdx < HI_MAPI_OSD_MAX_CNT, HI_MAPI_OSD_EHANDLE_ILLEGAL);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, pstAttr->u32DispNum != 0, HI_MAPI_OSD_EILLEGAL_PARAM);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, pstAttr->u32DispNum <= HI_MAPI_OSD_MAX_DISP_CNT, HI_MAPI_OSD_EILLEGAL_PARAM);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, pstAttr->stContent.enType < HI_MAPI_OSD_TYPE_BUTT, HI_MAPI_OSD_EILLEGAL_PARAM);

    HI_U32 i;
    for (i = 0; i < pstAttr->u32DispNum; i++) {
        CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, pstAttr->astDispAttr[i].enBindedMod < HI_MAPI_OSD_BINDMOD_BUTT,
            HI_MAPI_OSD_EILLEGAL_PARAM);
        CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, pstAttr->astDispAttr[i].enCoordinate <= HI_MAPI_OSD_COORDINATE_ABS_COOR,
            HI_MAPI_OSD_EILLEGAL_PARAM);
        if (pstAttr->astDispAttr[i].enBindedMod == HI_MAPI_OSD_BINDMOD_VENC) {
            CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, pstAttr->astDispAttr[i].enAttachDest < ATTACH_JPEG_BUTT,
                HI_MAPI_OSD_EILLEGAL_PARAM);
        }

        if ((pstAttr->astDispAttr[i].enBindedMod == HI_MAPI_OSD_BINDMOD_STITCH) &&
            (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_CIRCLE)) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "stitch module not support circle.\n");
            return HI_MAPI_OSD_EILLEGAL_PARAM;
        }

        if ((pstAttr->astDispAttr[i].enBindedMod == HI_MAPI_OSD_BINDMOD_VENC) &&
            (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_CIRCLE)) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "venc module not support circle.\n");
            return HI_MAPI_OSD_EILLEGAL_PARAM;
        }
    }

    if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_TIME) {
        CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, pstAttr->stContent.stTimeContent.enTimeFmt < HI_MAPI_OSD_TIMEFMT_BUTT,
            HI_MAPI_OSD_EILLEGAL_PARAM);
        CHECK_MAPI_NULL_PTR_RET(HI_MAPI_MOD_OSD, g_stOsdFonts.pfnGetFontMod, HI_MAPI_OSD_ENOFONT);
    } else if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_BITMAP) {
        CHECK_MAPI_NULL_PTR_RET(HI_MAPI_MOD_OSD, pstAttr->stContent.stBitmapContent.pData, HI_MAPI_OSD_ENULL_PTR);
    } else if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_STRING) {
        CHECK_MAPI_NULL_PTR_RET(HI_MAPI_MOD_OSD, g_stOsdFonts.pfnGetFontMod, HI_MAPI_OSD_ENOFONT);
    }

    s32Ret = OSD_CheckStitchModeAttr(pstAttr);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32Ret == HI_SUCCESS, s32Ret);

    return HI_SUCCESS;
}

static HI_VOID* OSD_TimeUpdateThread(HI_VOID* pvParam)
{
    MAPI_UNUSED(pvParam);
    HI_S32 s32Ret = 0;
    HI_S32 s32OsdIdx;
    time_t nowTime = 0;
    time_t lastTime = 0;
    struct tm stTime = {
        0,
    };
    prctl(PR_SET_NAME, __FUNCTION__, 0, 0, 0);

    while (g_bOsdTimeRun) {
        time(&nowTime);

        if (nowTime == lastTime) {
            MAPI_Usleep(MAPI_ADEC_WAIT_TIME_CHANGE_USLEEP_TIME);
            continue;
        } else {
            localtime_r(&nowTime, &stTime);

            for (s32OsdIdx = 0; s32OsdIdx < HI_MAPI_OSD_MAX_CNT; ++s32OsdIdx) {
                MUTEX_LOCK(g_astOSDParam[s32OsdIdx].mutexLock);

                if (g_astOSDParam[s32OsdIdx].stAttr.stContent.enType == HI_MAPI_OSD_TYPE_TIME &&
                    g_astOSDParam[s32OsdIdx].bStart) {
                    /*   Update OSD Time String   */
                    OSD_GetTimeStr(&stTime, g_astOSDParam[s32OsdIdx].stAttr.stContent.stTimeContent.enTimeFmt,
                                   g_astOSDParam[s32OsdIdx].szStr, HI_MAPI_OSD_MAX_STR_LEN);

                    /*   Update OSD Text Bitmap   */
                    s32Ret = OSD_UpdateTextBitmap(s32OsdIdx, &g_astOSDParam[s32OsdIdx].stAttr.stContent);

                    if (s32Ret != HI_SUCCESS) {
                        MUTEX_UNLOCK(g_astOSDParam[s32OsdIdx].mutexLock);
                        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "Update Text Bitmap failed\n");
                        continue;
                    }

                    /*   Update OSD Attribute   */
                    s32Ret = OSD_UpdateDisplay(s32OsdIdx, &g_astOSDParam[s32OsdIdx].stAttr);
                    if (s32Ret != HI_SUCCESS) {
                        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "Update Attribute failed\n");
                    }
                }

                MUTEX_UNLOCK(g_astOSDParam[s32OsdIdx].mutexLock);
            }

            lastTime = nowTime; /*   update time   */
        }

        MAPI_Usleep(MAPI_ADEC_WAIT_UPDATE_TIME_USLEEP_TIME);
    }

    return NULL;
}



HI_S32 HI_MAPI_OSD_Init(const HI_MAPI_OSD_FONTS_S* pstFonts)
{
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, g_bOsdInitFlg != HI_TRUE, HI_SUCCESS);
    if (pstFonts != NULL) {
        CHECK_MAPI_NULL_PTR_RET(HI_MAPI_MOD_OSD, pstFonts->pfnGetFontMod, HI_MAPI_OSD_ENULL_PTR);
        if (pstFonts->u32FontWidth % BYTE_BITS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "FontWidth must be a multiple of %d.", BYTE_BITS);
            return HI_MAPI_OSD_EILLEGAL_PARAM;
        }
        memcpy(&g_stOsdFonts, pstFonts, sizeof(HI_MAPI_OSD_FONTS_S));
    } else {
        memset(&g_stOsdFonts, 0, sizeof(HI_MAPI_OSD_FONTS_S));
    }

    HI_S32 s32Idx;
    HI_S32 s32Ret = HI_SUCCESS;
    /*   Init OSD Param   */
    for (s32Idx = 0; s32Idx < HI_MAPI_OSD_MAX_CNT; ++s32Idx) {
        MUTEX_INIT_LOCK(g_astOSDParam[s32Idx].mutexLock);
        MUTEX_LOCK(g_astOSDParam[s32Idx].mutexLock);
        memset(&g_astOSDParam[s32Idx].stAttr, 0, sizeof(HI_MAPI_OSD_ATTR_S));
        memset(&g_astOSDParam[s32Idx].stMaxSize, 0, sizeof(SIZE_S));
        g_astOSDParam[s32Idx].bInit = HI_FALSE;
        g_astOSDParam[s32Idx].bStart = HI_FALSE;
        g_astOSDParam[s32Idx].enRgnType = RGN_BUTT;
        memset(&g_astOSDParam[s32Idx].szStr, 0, sizeof(HI_CHAR) * HI_MAPI_OSD_MAX_STR_LEN);
        MUTEX_UNLOCK(g_astOSDParam[s32Idx].mutexLock);
    }

    if (pstFonts != NULL) {
        /*   Create Time OSD Update Thread   */
        g_bOsdTimeRun = HI_TRUE;
        s32Ret = pthread_create(&g_pOsdTimeTskId, NULL, OSD_TimeUpdateThread, NULL);

        if (s32Ret != HI_SUCCESS) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "create OSD_TimeUpdateThread failed:%s\n", strerror(errno));
            return HI_MAPI_OSD_ENOMEM;
        }
    }

    g_bOsdInitFlg = HI_TRUE;
    return HI_SUCCESS;
}



HI_S32 HI_MAPI_OSD_Deinit(HI_VOID)
{
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, g_bOsdInitFlg == HI_TRUE, HI_MAPI_OSD_ENOT_INITED);
    if (g_pOsdTimeTskId != 0) {
        /*   Destroy Time OSD Update Task   */
        g_bOsdTimeRun = HI_FALSE;
        pthread_join(g_pOsdTimeTskId, NULL);
    }

    HI_S32 s32Idx;
    HI_S32 s32Ret;
    for (s32Idx = 0; s32Idx < HI_MAPI_OSD_MAX_CNT; ++s32Idx) {
        MUTEX_LOCK(g_astOSDParam[s32Idx].mutexLock);
        /*   Stop Osd   */
        if (g_astOSDParam[s32Idx].bStart) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD[%d] is Started, try stop.\n", s32Idx);
            s32Ret = OSD_Stop(s32Idx);
            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD[%d] Stop error:%#x\n", s32Idx, s32Ret);
                MUTEX_UNLOCK(g_astOSDParam[s32Idx].mutexLock);
                return s32Ret;
            }
        }
        MUTEX_UNLOCK(g_astOSDParam[s32Idx].mutexLock);
        MUTEX_DESTROY(g_astOSDParam[s32Idx].mutexLock);
    }

    g_bOsdInitFlg = HI_FALSE;

    return HI_SUCCESS;
}

HI_S32 HI_MAPI_OSD_SetAttr(HI_S32 s32OsdIdx, HI_MAPI_OSD_ATTR_S* pstAttr)
{
    /*   Check Module Init or not   */
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, g_bOsdInitFlg == HI_TRUE, HI_MAPI_OSD_ENOT_INITED);
    HI_S32 s32Ret;
    s32Ret = OSD_CheckAttr(s32OsdIdx, pstAttr);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32Ret == HI_SUCCESS, s32Ret);

    SIZE_S stOsdMaxSize;
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[s32OsdIdx];
    OSD_GetMaxSize(pstAttr, &stOsdMaxSize);
    MUTEX_LOCK(pstOsdParam->mutexLock);

    /* pstAttr do not save time osd str ,so will use pstOsdParam->szStr save time osd and str osd content */
    if (pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_STRING) {
        memset(pstOsdParam->szStr, 0, HI_MAPI_OSD_MAX_STR_LEN);
        snprintf(pstOsdParam->szStr, HI_MAPI_OSD_MAX_STR_LEN, "%s", pstAttr->stContent.stStrContent.szStr);
    } else if(pstAttr->stContent.enType == HI_MAPI_OSD_TYPE_TIME) {
        OSD_GetTimeStr(NULL, pstAttr->stContent.stTimeContent.enTimeFmt, pstOsdParam->szStr,
            HI_MAPI_OSD_MAX_STR_LEN);
    }

    MAPI_INFO_TRACE(HI_MAPI_MOD_OSD, "RGN(%d) size increase[%d,%d->%d,%d], rebuild\n", s32OsdIdx,
        pstOsdParam->stMaxSize.u32Width, pstOsdParam->stMaxSize.u32Height,
        stOsdMaxSize.u32Width, stOsdMaxSize.u32Height);

    HI_BOOL bStart = pstOsdParam->bStart;
    if (bStart) {
        if (OSD_CheckIfRebuild(s32OsdIdx, pstAttr, &stOsdMaxSize)) {
            MAPI_INFO_TRACE(HI_MAPI_MOD_OSD, "RGN(%d) size increase[%d,%d->%d,%d], rebuild\n", s32OsdIdx,
                            pstOsdParam->stMaxSize.u32Width, pstOsdParam->stMaxSize.u32Height,
                            stOsdMaxSize.u32Width, stOsdMaxSize.u32Height);
            /*  rebuild RGN  */
            s32Ret = OSD_DestroyRgn(s32OsdIdx, &pstOsdParam->stAttr);
            if (s32Ret != HI_SUCCESS) {
                MUTEX_UNLOCK(pstOsdParam->mutexLock);
                return s32Ret;
            }

            s32Ret = OSD_CreateRgn(s32OsdIdx, pstAttr);
            if (s32Ret != HI_SUCCESS) {
                MUTEX_UNLOCK(pstOsdParam->mutexLock);
                return s32Ret;
            }

            pstOsdParam->stMaxSize.u32Width = stOsdMaxSize.u32Width;
            pstOsdParam->stMaxSize.u32Height = stOsdMaxSize.u32Height;
        } else {
            /*  Update RGN Content  */
            s32Ret = OSD_UpdateRgnContent(s32OsdIdx, pstAttr);
            if (s32Ret != HI_SUCCESS) {
                MAPI_ERR_TRACE(HI_MAPI_MOD_OSD,
                    "osd update rgn content fail,RgnHdl[%d] Error Code: [0x%08X]\n", s32OsdIdx, s32Ret);
                MUTEX_UNLOCK(pstOsdParam->mutexLock);
                return s32Ret;
            }

            s32Ret = OSD_UpdateDisplay(s32OsdIdx, pstAttr);
            if (s32Ret != HI_SUCCESS) {
                MUTEX_UNLOCK(pstOsdParam->mutexLock);
                return s32Ret;
            }
        }
    } else {
        pstOsdParam->stMaxSize.u32Width = stOsdMaxSize.u32Width;
        pstOsdParam->stMaxSize.u32Height = stOsdMaxSize.u32Height;
    }

    memcpy(&pstOsdParam->stAttr, pstAttr, sizeof(HI_MAPI_OSD_ATTR_S));
    pstOsdParam->bInit = HI_TRUE;
    MUTEX_UNLOCK(pstOsdParam->mutexLock);
    return HI_SUCCESS;
}

HI_S32 HI_MAPI_OSD_GetAttr(HI_S32 s32OsdIdx, HI_MAPI_OSD_ATTR_S* pstAttr)
{
    /*   Check Module Init or not   */
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, g_bOsdInitFlg == HI_TRUE, HI_MAPI_OSD_ENOT_INITED);
    /*   Check Input Param   */
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32OsdIdx >= 0, HI_MAPI_OSD_EHANDLE_ILLEGAL);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32OsdIdx < HI_MAPI_OSD_MAX_CNT, HI_MAPI_OSD_EHANDLE_ILLEGAL);
    CHECK_MAPI_NULL_PTR_RET(HI_MAPI_MOD_OSD, pstAttr, HI_MAPI_OSD_ENULL_PTR);

    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[s32OsdIdx];
    MUTEX_LOCK(pstOsdParam->mutexLock);

    /*   Check OSD Attrbute init or not   */
    if (!pstOsdParam->bInit) {
        MUTEX_UNLOCK(pstOsdParam->mutexLock);
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD[%d] not init yet!\n", s32OsdIdx);
        return HI_MAPI_OSD_ENOT_PERM;
    }

    memcpy(pstAttr, &pstOsdParam->stAttr, sizeof(HI_MAPI_OSD_ATTR_S));
    MUTEX_UNLOCK(pstOsdParam->mutexLock);
    return HI_SUCCESS;
}

HI_S32 HI_MAPI_OSD_Start(HI_S32 s32OsdIdx)
{
    /*   Check Module Init or not   */
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, g_bOsdInitFlg == HI_TRUE, HI_MAPI_OSD_ENOT_INITED);
    /*   Check Input Param   */
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32OsdIdx >= 0, HI_MAPI_OSD_EHANDLE_ILLEGAL);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32OsdIdx < HI_MAPI_OSD_MAX_CNT, HI_MAPI_OSD_EHANDLE_ILLEGAL);

    HI_S32 s32Ret;
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[s32OsdIdx];

    MUTEX_LOCK(pstOsdParam->mutexLock);

    /*   Check OSD Attrbute init or not   */
    if (!pstOsdParam->bInit) {
        MUTEX_UNLOCK(pstOsdParam->mutexLock);
        MAPI_ERR_TRACE(HI_MAPI_MOD_OSD, "OSD[%d] not init yet!\n", s32OsdIdx);
        return HI_MAPI_OSD_ENOT_PERM;
    }

    /*   Check OSD stop or not   */
    if (pstOsdParam->bStart) {
        MUTEX_UNLOCK(pstOsdParam->mutexLock);
        MAPI_INFO_TRACE(HI_MAPI_MOD_OSD, "OSD[%d] has already started!\n", s32OsdIdx);
        return HI_SUCCESS;
    }

    s32Ret = OSD_Start(s32OsdIdx);
    MUTEX_UNLOCK(pstOsdParam->mutexLock);
    return s32Ret;
}

HI_S32 HI_MAPI_OSD_Stop(HI_S32 s32OsdIdx)
{
    /*   Check Module Init or not   */
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, g_bOsdInitFlg == HI_TRUE, HI_MAPI_OSD_ENOT_INITED);
    /*   Check Input Param   */
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32OsdIdx >= 0, HI_MAPI_OSD_EHANDLE_ILLEGAL);
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, s32OsdIdx < HI_MAPI_OSD_MAX_CNT, HI_MAPI_OSD_EHANDLE_ILLEGAL);

    HI_S32 s32Ret;
    OSD_PARAM_S *pstOsdParam = &g_astOSDParam[s32OsdIdx];

    MUTEX_LOCK(pstOsdParam->mutexLock);

    /*   Check OSD Attrbute init or not   */
    if (!pstOsdParam->bInit) {
        MUTEX_UNLOCK(pstOsdParam->mutexLock);
        return HI_SUCCESS;
    }

    /*   Check OSD stop or not   */
    if (!pstOsdParam->bStart) {
        MUTEX_UNLOCK(pstOsdParam->mutexLock);
        return HI_SUCCESS;
    }

    s32Ret = OSD_Stop(s32OsdIdx);
    pstOsdParam->stMaxSize.u32Width = 0;
    pstOsdParam->stMaxSize.u32Height = 0;
    MUTEX_UNLOCK(pstOsdParam->mutexLock);
    return s32Ret;
}

HI_S32 HI_MAPI_OSD_Batch(HI_U32 u32Batch, HI_BOOL bShow)
{
    CHECK_MAPI_BOOL_RET(HI_MAPI_MOD_OSD, g_bOsdInitFlg == HI_TRUE, HI_MAPI_OSD_ENOT_INITED);
    HI_S32 s32OsdIdx;
    HI_U32 u32DispIdx;
    HI_BOOL bUpdateContent;
    for (s32OsdIdx = 0; s32OsdIdx < HI_MAPI_OSD_MAX_CNT; ++s32OsdIdx) {
        if (!g_astOSDParam[s32OsdIdx].bStart) {
            continue;
        }

        bUpdateContent = HI_FALSE;

        MUTEX_LOCK(g_astOSDParam[s32OsdIdx].mutexLock);
        for (u32DispIdx = 0; u32DispIdx < g_astOSDParam[s32OsdIdx].stAttr.u32DispNum; ++u32DispIdx) {
            if (g_astOSDParam[s32OsdIdx].stAttr.astDispAttr[u32DispIdx].u32Batch == u32Batch) {
                bUpdateContent = HI_TRUE;
                g_astOSDParam[s32OsdIdx].stAttr.astDispAttr[u32DispIdx].bShow = bShow;
            }
        }

        /* nonentity u32Batch, no need update display */
        if (bUpdateContent == HI_TRUE) {
            OSD_UpdateDisplay(s32OsdIdx, &g_astOSDParam[s32OsdIdx].stAttr);
        }

        MUTEX_UNLOCK(g_astOSDParam[s32OsdIdx].mutexLock);
    }

    return HI_SUCCESS;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /*   End of #ifdef __cplusplus   */
